package ru.compft.common.dao.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import ru.compft.common.dao.ModuleDao;
import ru.compft.common.data.Module;
import ru.compft.common.data.ModulePage;
import ru.compft.common.utils.CommonUtils;
import ru.compft.common.utils.GlobalConstants;
import ru.compft.common.utils.StringConverter;

import java.io.*;
import java.util.LinkedList;
import java.util.List;

/**
 * User: VVasiliev
 * Date: 14.06.12
 * Time: 14:08
 * Пример реализации функциональности работы с модулями
 * Нужен для демонстрационной версии
 */
public class ExampleModuleDaoImpl implements ModuleDao {
    private static final Logger logger = LoggerFactory.getLogger(ExampleModuleDaoImpl.class);

    private String MODULES_CSV = "/modules.csv";
    private String MODULES_PAGES_CSV = "/modulesPages.csv";

    @Override
    public List<Module> getAllModules() {
        return readFromFile();
    }

    @Override
    public List<Module> getModules(int from, int count) {
        return CommonUtils.getPartOfList(from, count, readFromFile());
    }

    @Override
    public int countAllModules() {
        return readFromFile().size();
    }

    @Override
    public Module getModuleById(Long moduleId) {
        final List<Module> moduleList = readFromFile();
        if (!CollectionUtils.isEmpty(moduleList)) {
            for (Module module : moduleList) {
                if (module.getId().equals(moduleId))
                    return module;
            }
        }
        return null;
    }

    @Override
    public Module getModuleByCode(String code) {
        final List<Module> moduleList = readFromFile();
        if (!CollectionUtils.isEmpty(moduleList)) {
            for (Module module : moduleList) {
                if (module.getCode().equals(code))
                    return module;
            }
        }
        return null;
    }

//    @Override
//    public Module getModuleByPath(String path) {
//        final List<Module> moduleList = readFromFile();
//        if (!CollectionUtils.isEmpty(moduleList)) {
//            for (Module module : moduleList) {
//                if (module.getPath().equals(path))
//                    return module;
//            }
//        }
//        return null;
//    }

    public Long generateId() {
        return System.currentTimeMillis();
    }

    @Override
    public Module update(Module module) {
        return module;
    }

    @Override
    public List<ModulePage> getAllModulePages() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public List<ModulePage> getAllPagesToModule(Long moduleId) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

//    @Override
//    public List<ModulePage> getAllPagesToModules() {
//        return readModulePagesFromFile();
//    }

    /**
     * Считываем данные из файла
     *
     * @return
     */
    private List<Module> readFromFile() {
        // Считываем из файла меппинг userId -> List<roleId>
        final List<ModulePage> modulePagesList = readModulePagesFromFile();
        final List<Module> result = new LinkedList<Module>();
        BufferedReader br = null;

        try {
            final String fullPath = System.getProperty(GlobalConstants.USER_DIR_PROP_NAME) + GlobalConstants.CACHE_DATA + MODULES_CSV;
            final File resourceFile = new File(fullPath);
            if (!resourceFile.exists())
                throw new FileNotFoundException("File " + fullPath + " not found.");

            br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(resourceFile), GlobalConstants.DEFAULT_ENCODING));

            String strLine;
            boolean firstString = true;

            //Read File Line By Line
            while ((strLine = br.readLine()) != null) {
                // пропускаем первую строку, т.к. там лежат имена колонок
                if (firstString) {
                    firstString = false;
                    continue;
                }

                strLine = strLine.replaceAll(GlobalConstants.DOUBLE_QUOTA, GlobalConstants.EMPTY_STRING);

                final String[] fieldArray = strLine.split(GlobalConstants.DOT_COMMA);
                if (fieldArray.length != 7)
                    throw new Exception("Field array more or less than 7 records");

                final Long id = Long.valueOf(fieldArray[0].trim());
                final String code = fieldArray[1].trim();
                final String name = fieldArray[2].trim();
                final String path = fieldArray[3].trim();
                final String description = fieldArray[4].trim();
                final boolean visible = GlobalConstants.Y.equals(fieldArray[5].trim());
                final int order = Integer.parseInt(fieldArray[6].trim());

                // создаем модуль
//                final Module module = new Module(id, code, name, path, description, visible, order);
                final Module module = new Module();
                module.setId(id);
                module.setCode(code);
                module.setName(name);
                module.setDescription(description);
                module.setVisible(visible);
                module.setOrder(order);

                // добавляем ему страницы
                if (!CollectionUtils.isEmpty(modulePagesList)) {
                    for (ModulePage modulePage : modulePagesList) {
                        if (modulePage.getModuleId().equals(id)) {
                            module.addPage(modulePage);
                        }
                    }
                }

                result.add(module);
            }
        } catch (IOException e) {
            logger.error("Can't read from file " + MODULES_CSV, e);
        } catch (Exception e) {
            logger.error("Error while read from file " + MODULES_CSV, e);
        } finally {
            if (br != null)
                try {
                    br.close();
                } catch (IOException e) {
                    // ignore
                }
        }

        return result;
    }

    /**
     * Инициализация кеша
     */
    private List<ModulePage> readModulePagesFromFile() {
        final List<ModulePage> modulePageList = new LinkedList<ModulePage>();
        BufferedReader br = null;

        try {
            final String fullPath = System.getProperty(GlobalConstants.USER_DIR_PROP_NAME) + GlobalConstants.CACHE_DATA + MODULES_PAGES_CSV;
            final File resourceFile = new File(fullPath);
            if (!resourceFile.exists())
                throw new FileNotFoundException("File " + fullPath + " not found.");

            br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(resourceFile), GlobalConstants.DEFAULT_ENCODING));

            String strLine;
            boolean firstString = true;

            //Read File Line By Line
            while ((strLine = br.readLine()) != null) {
                // пропускаем первую строку, т.к. там лежат имена колонок
                if (firstString) {
                    firstString = false;
                    continue;
                }

                strLine = strLine.replaceAll(GlobalConstants.DOUBLE_QUOTA, GlobalConstants.EMPTY_STRING);

                final String[] fieldArray = strLine.split(GlobalConstants.DOT_COMMA);
                if (fieldArray.length != 8)
                    throw new Exception("Field array more or less than 8 records");

                final Long id = Long.valueOf(fieldArray[0].trim());
                final Long moduleId = Long.valueOf(fieldArray[1].trim());
                final String code = fieldArray[2].trim();
                final String name = fieldArray[3].trim();
                final String path = fieldArray[4].trim();
                final String description = fieldArray[5].trim();
                final boolean visible = Boolean.parseBoolean(fieldArray[6].trim());
                final int order = Integer.parseInt(fieldArray[7].trim());

                ModulePage modulePage = new ModulePage(id, moduleId, code, name, description, visible, order);
                modulePageList.add(modulePage);
            }
        } catch (IOException e) {
            logger.error("Can't read from file " + MODULES_PAGES_CSV, e);
        } catch (Exception e) {
            logger.error("Error while read from file " + MODULES_PAGES_CSV, e);
        } finally {
            if (br != null)
                try {
                    br.close();
                } catch (IOException e) {
                    // ignore
                }
        }
        return modulePageList;
    }

    /**
     * Записываем данные в файл
     *
     * @return
     */
    private boolean writeToFile(Module module) {
        BufferedWriter out = null;

        try {
            final String fullPath = System.getProperty(GlobalConstants.USER_DIR_PROP_NAME) + GlobalConstants.CACHE_DATA + MODULES_CSV;
            final File resourceFile = new File(fullPath);
            if (!resourceFile.exists())
                throw new FileNotFoundException("File " + fullPath + " not found.");

            // создаем строку вида: "ID";"CODE";"NAME";"PATH";"VISIBLE";"DESCRIPTION"
            final String csvRecord = StringConverter.createCsvRecord(new String[]{module.getId().toString(), module.getCode(),
                    module.getName(), Boolean.toString(module.isVisible()), module.getDescription()});

            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(resourceFile, true), GlobalConstants.DEFAULT_ENCODING));

            out.write(csvRecord);
            out.flush();

            return true;
        } catch (IOException e) {
            logger.error("Can't write to file " + MODULES_CSV, e);
        } catch (Exception e) {
            logger.error("Error while write to file " + MODULES_CSV, e);
        } finally {
            if (out != null)
                try {
                    out.close();
                } catch (IOException e) {
                    // ignore
                }
        }
        return false;
    }
}
